<template>
  <div class="app-container">
    <div class="filter-container">
      <el-input
        v-model="listQuery.jobDesc"
        placeholder="名称"
        style="width: 200px"
        class="filter-item"
        maxlength="50"
        show-word-limit
        @keyup.enter.native="handleFilter"
      />
      <el-button
        class="filter-item"
        type="primary"
        icon="el-icon-search"
        @click="handleFilter"
      >
        搜索
      </el-button>
      <el-button
        class="filter-item"
        style="margin-left: 10px"
        type="primary"
        icon="el-icon-edit"
        @click="handleCreate"
      >
        添加任务
      </el-button>

      <el-button
        class="filter-item"
        style="margin-left: 10px"
        type="primary"
        icon="el-icon-refresh"
        @click="getList"
      >
        刷新列表
      </el-button>
    </div>

    <el-table
      :key="tableKey"
      v-loading="listLoading"
      :data="list"
      border
      fit
      highlight-current-row
      style="width: 100%"
    >
      <el-table-column label="ID" align="center" width="50">
        <template slot-scope="{ row }">
          <span>{{ row.id }}</span>
        </template>
      </el-table-column>
      <el-table-column
        label="任务名称"
        min-width="20%"
        align="center"
        show-overflow-tooltip
      >
        <template slot-scope="{ row }">
          <span>{{ row.jobDesc }}</span>
        </template>
      </el-table-column>
      <el-table-column label="CRON" min-width="10%" align="center">
        <template slot-scope="{ row }">
          <span>{{ row.scheduleConf }}</span>
        </template>
      </el-table-column>
      <el-table-column label="状态" width="150" align="center">
        <template slot-scope="{ row }">
          <el-tag
            type="success"
            v-show="row.triggerStatus == 1"
            :disable-transitions="true"
            >启动</el-tag
          >
          <el-tag
            type="info"
            v-show="row.triggerStatus == 0"
            :disable-transitions="true"
            >停止</el-tag
          >
          <el-tag
            type="danger"
            v-show="row.triggerStatus != 1 && row.triggerStatus != 0"
            :disable-transitions="true"
            >异常</el-tag
          >
          <el-switch
            v-model="row.triggerStatus"
            :active-value="1"
            :inactive-value="0"
            active-color="#13ce66"
            inactive-color="#ff4949"
            @change="changeTriggerStatus(row.triggerStatus, row.id)"
          ></el-switch>
        </template>
      </el-table-column>
      <el-table-column
        label="执行器"
        min-width="5%"
        align="center"
        show-overflow-tooltip
      >
        <template slot-scope="{ row }">
          <el-popover placement="right" min-width="200" trigger="click">
            <el-descriptions
              title="执行器"
              direction="vertical"
              :column="1"
              border
            >
              <el-descriptions-item label="名称">{{
                executor.title
              }}</el-descriptions-item>
              <el-descriptions-item label="AppName">{{
                executor.appname
              }}</el-descriptions-item>
              <el-descriptions-item label="地址">{{
                executor.addressList
              }}</el-descriptions-item>
            </el-descriptions>
            <el-button slot="reference" @click="getExecutor(row.jobGroup)"
              >查看</el-button
            >
          </el-popover>
        </template>
      </el-table-column>
      <el-table-column
        label="下次触发时间"
        min-width="5%"
        align="center"
        show-overflow-tooltip
      >
        <template slot-scope="{ row }">
          <el-popover placement="right" min-width="200" trigger="click">
            <p v-for="item in nextTriggerTimeList" v-text="item"></p>
            <el-button
              slot="reference"
              @click="getNextTriggerTime(row.scheduleConf)"
              >查看</el-button
            >
          </el-popover>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" min-width="10%" align="center">
        <template slot-scope="{ row }">
          <span>{{ row.addTime }}</span>
        </template>
      </el-table-column>
      <el-table-column
        label="操作"
        align="center"
        min-width="10%"
        class-name="small-padding fixed-width"
      >
        <template slot-scope="{ row }">
          <el-dropdown>
            <span class="el-dropdown-link">
              <el-button type="text">操作</el-button
              ><i class="el-icon-arrow-down"></i>
            </span>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item
                ><el-button type="text" @click="trigger(row.id)"
                  >执行一次</el-button
                >
              </el-dropdown-item>
              <el-dropdown-item
                ><el-button type="text" @click="handleLog(row.id)"
                  >查看日志</el-button
                ></el-dropdown-item
              >
              <el-dropdown-item
                ><el-button type="text" @click="handleUpdate(row)"
                  >编辑</el-button
                ></el-dropdown-item
              >
              <el-dropdown-item
                ><el-button type="text" @click="handleJobDelete(row.id)"
                  >删除</el-button
                ></el-dropdown-item
              >
            </el-dropdown-menu>
          </el-dropdown>
        </template>
      </el-table-column>
    </el-table>

    <pagination
      v-show="total > 0"
      :total="total"
      :page.sync="listQuery.page"
      :limit.sync="listQuery.limit"
      @pagination="getList"
    />

    <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
      <el-form
        ref="dataForm"
        :rules="rules"
        :model="tempData"
        label-position="left"
        label-width="150px"
        style="margin-left: 50px"
      >
        <el-form-item prop="uuid" v-show="false">
          <el-input v-model="tempData.uuid" />
        </el-form-item>
        <el-row>
          <el-col :span="12">
            <el-form-item prop="jobGroup" label="执行器">
              <el-select
                v-model="tempData.jobGroup"
                class="filter-item"
                placeholder="请选择执行器"
              >
                <el-option
                  v-for="item in executorlist"
                  :key="item.id"
                  :label="item.title"
                  :value="item.id"
                ></el-option>
              </el-select>
            </el-form-item>
            <el-form-item prop="executorRouteStrategy" label="路由策略">
              <el-select
                v-model="tempData.executorRouteStrategy"
                class="filter-item"
                placeholder="请选择路由策略"
              >
                <el-option
                  v-for="item in this.executorRouteStrategyList"
                  :key="item.key"
                  :label="item.label"
                  :value="item.value"
                ></el-option>
              </el-select>
            </el-form-item>
            <el-form-item prop="executorBlockStrategy" label="阻塞处理">
              <el-select
                v-model="tempData.executorBlockStrategy"
                class="filter-item"
                placeholder="请选择阻塞处理策略"
              >
                <el-option
                  v-for="item in executorBlockStrategyList"
                  :key="item.key"
                  :label="item.label"
                  :value="item.value"
                ></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item prop="jobDesc" label="任务名称">
              <el-input
                v-model="tempData.jobDesc"
                placeholder="任务名称"
                maxlength="50"
                show-word-limit
              /> </el-form-item
            ><el-form-item prop="scheduleConf" label="CRON">
              <el-input
                v-model="tempData.scheduleConf"
                placeholder="调度规则CRON"
              /> </el-form-item
            ><el-form-item prop="executorFailRetryCount" label="失败重试次数">
              <el-input-number
                v-model="tempData.executorFailRetryCount"
                controls-position="right"
                :min="0"
                :max="10"
              ></el-input-number></el-form-item
            ><el-form-item prop="executorTimeout" label="超时时间(秒)">
              <el-input-number
                v-model="tempData.executorTimeout"
                controls-position="right"
                :step="30"
                :min="0"
                :max="600"
              ></el-input-number></el-form-item
          ></el-col>
        </el-row>
        <el-row
          ><el-col :span="24"
            ><el-form-item prop="jobDataxJson" label="JSON">
              <!-- <el-input
                v-model="tempData.jobDataxJson"
                type="textarea"
                :rows="10"
                placeholder="请输入Datax JSON"
              >
              </el-input> -->
              <codemirror
                v-model="tempData.jobDataxJson"
                :options="cmOptions2"
              ></codemirror> </el-form-item></el-col
        ></el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="close"> 取消 </el-button>
        <el-button
          type="primary"
          @click="dialogStatus === 'create' ? createData() : updateData()"
        >
          确认
        </el-button>
      </div>
    </el-dialog>

    <el-dialog title="查看日志" :visible.sync="dialogLogFormVisible">
      
      <el-button type="text"  @click="getLogList()">刷新列表</el-button>
        |
        <el-dropdown @command="handleClearLog">
        <span class="el-dropdown-link" style="cursor: pointer; color: #409eff">
          清除历史日志<i class="el-icon-arrow-down el-icon--right"></i>
        </span>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item command="1"
            >清理一个月之前日志数据</el-dropdown-item
          >
          <el-dropdown-item command="2"
            >清理三个月之前日志数据</el-dropdown-item
          >
          <el-dropdown-item command="5"
            >清理一千条以前日志数据</el-dropdown-item
          >
          <el-dropdown-item command="9">清理所有日志数据</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      <el-table
        v-loading="listJobLoading"
        :data="jobList"
        border
        fit
        highlight-current-row
        style="width: 100%"
      >
        <el-table-column label="ID" align="center" width="50">
          <template slot-scope="{ row }">
            <span>{{ row.id }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="调度结果"
          min-width="5%"
          align="center"
          show-overflow-tooltip
        >
          <template slot-scope="{ row }">
            <el-tag type="danger" v-show="row.triggerCode != 200">失败</el-tag>
            <el-tag type="success" v-show="row.triggerCode == 200">成功</el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="调度时间"
          min-width="10%"
          align="center"
          show-overflow-tooltip
        >
          <template slot-scope="{ row }"
            ><span>{{ row.triggerTime }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="执行结果"
          min-width="5%"
          align="center"
          show-overflow-tooltip
        >
          <template slot-scope="{ row }">
            <el-tag
              type="warning"
              v-show="row.handleCode == 0 && row.triggerCode == 200"
              >执行中</el-tag
            >
            <el-tag
              type="info"
              v-show="row.handleCode == 0 && row.triggerCode != 200"
              >未执行</el-tag
            >
            <el-tag
              type="danger"
              v-show="row.handleCode != 200 && row.handleCode != 0"
              >失败</el-tag
            >
            <el-tag type="success" v-show="row.handleCode == 200">成功</el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="执行时间"
          min-width="10%"
          align="center"
          show-overflow-tooltip
        >
          <template slot-scope="{ row }"
            ><span>{{ row.handleTime }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="操作"
          min-width="10%"
          align="center"
          show-overflow-tooltip
          ><template slot-scope="{ row }">
            <el-button @click="showLogDetail(row)">查看</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        :hide-on-single-page="true"
        :page-sizes="['5']"
        v-show="jobTotal > 0"
        :total="jobTotal"
        :page.sync="listLogQuery.page"
        :limit.sync="listLogQuery.limit"
        @pagination="getLogList"
      />
      <el-tabs
        type="border-card"
        v-show="logDetailVisible"
        v-model="logDetailShow"
      >
        <el-tab-pane label="详细日志" name="logDetail"
          ><el-button
            :loading="this.getLogDetailLoad"
            type="text"
            @click="getLogDetail()"
            >刷新日志</el-button
          >
          <!-- <el-input
            type="textarea"
            v-model="logDetail"
            :readonly="true"
            :autosize="{ minRows: 6, maxRows: 10 }"
          ></el-input> 
            -->
          <codemirror
            :value="this.logDetail"
            ref="codemirror1"
            :options="cmOptions1"
          ></codemirror>
        </el-tab-pane>
        <el-tab-pane label="调度日志" name="triggerMsg">
          <div v-html="triggerMsg"></div>
        </el-tab-pane>
        <el-tab-pane label="执行日志" name="handleMsg"
          ><div v-html="handleMsg"></div
        ></el-tab-pane>
      </el-tabs>
    </el-dialog>
  </div>
</template>

<script>
import Pagination from "@/components/Pagination";
import { codemirror } from "vue-codemirror";
import "codemirror/lib/codemirror.css";
import {
  listExecutor,
  queryExecutor,
  listExecutorRouteStrategy,
  listExecutorBlockStrategy,
} from "@/api/executor";
import { listLog, clearLog, queryLog } from "@/api/log";
import {
  listJob,
  deleteJob,
  updateJob,
  addJob,
  stopJob,
  startJob,
  triggerJob,
  nextTriggerTime,
} from "@/api/job";

export default {
  components: { Pagination, codemirror },
  data() {
    return {
      cmOptions1: {
        mode: "application/json", //模式
        theme: "base16-dark", // 主题
        lineNumbers: true, //是否显示行号
        line: true,
        readOnly: "nocursor",
      },
      cmOptions2: {
        mode: "application/json", //模式
        theme: "base16-light", // 主题
        lineNumbers: true, //是否显示行号
        line: true,
        readOnly: false,
        placeholder: "请输入Datax JSON",
      },
      tableKey: 0,
      //列表总数
      total: 0,
      //任务列表加载标识位
      listLoading: true,
      //任务列表
      list: [],
      //任务查询参数
      listQuery: {
        page: 1,
        limit: 20,
        jobGroup: 0,
        triggerStatus: -1,
        jobDesc: "",
      },
      listExecutorQuery: {
        page: 1,
        limit: 999,
        appname: undefined,
        title: undefined,
      },
      listLogQuery: {
        page: 1,
        limit: 5,
        jobGroup: 0,
        jobId: 0,
        logStatus: 0,
        filterTime: null,
      },
      tempData: {},
      dialogFormVisible: false,
      dialogStatus: "",
      textMap: {
        update: "编辑任务",
        create: "添加任务",
      },
      rules: {
        jobGroup: [
          { required: true, message: "请选择执行器", trigger: "change" },
        ],
        scheduleConf: [
          { required: true, message: "请输入CRON表达式", trigger: "change" },
        ],
        jobDesc: [
          { required: true, message: "请输入任务名称", trigger: "change" },
          {
            min: 4,
            max: 50,
            message: "任务名称长度为4到50",
            trigger: "blur",
          },
        ],
      },
      downloadLoading: false,
      statusMap: ["停止", "启动"],

      cronPopover: false,

      executorlist: [],
      executorTotal: 0,

      executorBlockStrategyList: [],
      executorRouteStrategyList: [],

      nextTriggerTimeList: "",

      executor: {
        appname: "",
        title: "",
        addressList: "",
      },

      dialogLogFormVisible: false,

      jobList: [],
      jobTotal: 0,
      listJobLoading: true,
      listLogDetailQuery: {},
      triggerMsg: "",
      handleMsg: "",
      logDetail: "",
      logDetailFromLine: 0,
      logDetailToLine: 0,
      logDetailVisible: false,
      logDetailShow: "logDetail",
      logJobName: "",
      getLogDetailLoad: false,
    };
  },
  created() {
    this.getList();
  },
  methods: {
    //执行器配置项列表
    async getExecutorConfig() {
      this.executorRouteStrategyList = await listExecutorRouteStrategy().then(
        (response) => {
          return response.data;
        }
      );
      this.executorBlockStrategyList = await listExecutorBlockStrategy().then(
        (response) => {
          return response.data;
        }
      );
    },
    //执行器获取列表
    async getExecutorlist() {
      const data = await listExecutor(this.listExecutorQuery).then(
        (response) => {
          return response.data;
        }
      );
      if (data.total > 999) {
        this.listExecutorQuery.limit = data.total;
        data = await listExecutor(this.listExecutorQuery).then((response) => {
          return response.data;
        });
      }
      this.executorlist = data.list;
      this.executorTotal = data.total;
    },
    //执行器获取列表
    async getExecutor(id) {
      this.executor.appname = "";
      this.executor.title = "";
      this.executor.addressList = "";
      const data = await queryExecutor(id).then((response) => {
        return response.data;
      });
      this.executor.appname = data.appname;
      this.executor.title = data.title;
      this.executor.addressList = data.addressList;
    },
    //获取列表
    async getList() {
      this.listLoading = true;
      const data = await listJob(this.listQuery).then((response) => {
        return response.data;
      });
      this.list = data.list;
      this.total = data.total;
      setTimeout(() => {
        this.listLoading = false;
      }, 1 * 1000);
    },
    //停止/开启任务
    async changeTriggerStatus(status, id) {
      if (status == 1) {
        try {
          await startJob(id);
          this.$notify({
            message: "启动成功",
            type: "success",
            duration: 2000,
          });
        } catch (error) {
          this.$notify({
            message: "启动失败",
            type: "error",
            duration: 2000,
          });
        }
        return;
      } else if (status == 0) {
        try {
          await stopJob(id);
          this.$notify({
            message: "关闭成功",
            type: "success",
            duration: 2000,
          });
        } catch (error) {
          this.$notify({
            message: "关闭失败",
            type: "error",
            duration: 2000,
          });
        }
        return;
      }
    },
    //查询任务下一次执行时间
    async getNextTriggerTime(cron) {
      this.nextTriggerTimeList = "";
      const data = await nextTriggerTime(cron).then((response) => {
        return response.data;
      });
      this.nextTriggerTimeList = data;
    },
    async trigger(id) {
      try {
        await triggerJob(id);
        this.$notify({
          message: "触发任务成功",
          type: "success",
          duration: 2000,
        });
      } catch (error) {
        this.$notify({
          message: "触发任务失败",
          type: "error",
          duration: 2000,
        });
      }
      return;
    },
    //搜索
    handleFilter() {
      this.listQuery.page = 1;
      this.getList();
    },
    //弹出添加框
    async handleCreate() {
      this.resetTemp();
      this.dialogStatus = "create";
      this.dialogFormVisible = true;
      await this.getExecutorlist();
      await this.getExecutorConfig();
      this.$nextTick(() => {
        this.$refs["dataForm"].clearValidate();
      });
    },
    //添加任务
    createData() {
      this.$refs["dataForm"].validate((valid) => {
        if (valid) {
          addJob(this.tempData).then((response) => {
            if (response) {
              this.$notify({
                message: "添加成功",
                type: "success",
                duration: 2000,
              });
              this.close();
              this.getList();
            }
          });
        }
      });
    },
    //更新任务
    async updateData() {
      this.$refs["dataForm"].validate((valid) => {
        if (valid) {
          console.log(this.tempData)
          updateJob(this.tempData).then((response) => {
            if (response) {
              this.$notify({
                message: "更新成功",
                type: "success",
                duration: 2000,
              });
              this.close();
              this.getList();
            }
          });
        }
      });
    },
    //关闭对话框
    close() {
      this.dialogFormVisible = false;
      this.resetTemp();
    },
    //初始化任务新增和编辑对话框
    resetTemp() {
      this.tempData = {
        jobDesc: "",
        scheduleConf: "",
        executorFailRetryCount: 0,
        executorTimeout: 0,
        jobDataxJson: "",
        executorBlockStrategy: "SERIAL_EXECUTION",
        executorRouteStrategy: "ROUND",
      };
      this.$nextTick(() => {
        this.$refs["dataForm"].clearValidate();
      });
    },

    //打开编辑任务对话框
    async handleUpdate(row) {
      this.resetTemp();
      this.tempData = Object.assign({}, row);
      this.dialogStatus = "update";
      this.dialogFormVisible = true;
      await this.getExecutorlist();
      await this.getExecutorConfig();
      this.$nextTick(() => {
        this.$refs["dataForm"].clearValidate();
      });
    },

    //删除任务
    async handleJobDelete(id) {
      const confirmRes = await this.$confirm(
        "此操作将永久删除该数据, 是否继续?",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      ).catch((err) => console.log(err));
      if (confirmRes == "confirm") {
        let response = await deleteJob(id);
        if (response) {
          this.$notify({
            message: "删除成功",
            type: "success",
            duration: 2000,
          });
        } else {
          this.$notify({
            message: "删除失败",
            type: "error",
            duration: 2000,
          });
        }
        this.getList();
      }
    },

    //打开日志对话框
    async handleLog(id) {
      this.dialogLogFormVisible = true;
      this.logDetailVisible = false;
      this.triggerMsg = "";
      this.handleMsg = "";
      this.listLogQuery = {
        page: 1,
        limit: 5,
        jobGroup: 0,
        jobId: id,
        logStatus: 0,
        filterTime: null,
      };
      this.getLogList();
    },

    //查询日志列表
    async getLogList() {
      this.logDetailVisible = false;
      this.triggerMsg = "";
      this.handleMsg = "";
      this.listJobLoading = true;
      const data = await listLog(this.listLogQuery).then((response) => {
        return response.data;
      });
      this.jobList = data.list;
      this.jobTotal = data.total;
      setTimeout(() => {
        this.listJobLoading = false;
      }, 1 * 1000);
    },

    //打开日志显示tab
    async showLogDetail(row) {
      this.logId = row.id;
      this.listJobLoading = true;
      this.logDetailVisible = false;
      this.logDetailShow = "logDetail";
      if (row.triggerMsg) {
        this.triggerMsg = row.triggerMsg.replace(/\r\n/g, "<br>");
      } else {
        this.triggerMsg = "";
      }
      if (row.handleMsg) {
        this.handleMsg = row.handleMsg.replace(/\r\n/g, "<br>");
      } else {
        this.handleMsg = "";
      }
      var triggerTime = Date.parse(row.triggerTime);
      this.listLogDetailQuery = {
        executorAddress: row.executorAddress,
        triggerTime: triggerTime,
        logId: row.id,
        fromLineNum: this.logDetailFromLine,
      };

      this.logDetail = "";
      this.logDetailVisible = true;
      await this.getLogDetail();

      setTimeout(() => {
        this.listJobLoading = false;
      }, 1000);
    },

    //获得详细日志
    async getLogDetail() {
      this.getLogDetailLoad = true;
      const data = await queryLog(this.listLogDetailQuery).then((response) => {
        return response.data.content;
      });
      if (data) {
        if (
          data.end &&
          this.listLogDetailQuery.fromLineNum >= data.toLineNum + 1
        ) {
          setTimeout(() => {
            this.getLogDetailLoad = false;
          }, 1000);
          return;
        }
        this.listLogDetailQuery.fromLineNum = data.toLineNum + 1;
        if (data.logContent) {
          this.logDetail += data.logContent.replace(/<br>/g, "\r\n");
          // this.logDetail += data.logContent;
        } else {
          this.logDetail += "";
        }
      } else {
        this.logDetail += "";
      }
      setTimeout(() => {
        this.getLogDetailLoad = false;
      }, 1000);
    },

    async handleClearLog(command) {
      var param = {
        type: command,
        jobGroup: this.listLogQuery.jobGroup,
        jobId: this.listLogQuery.jobId,
      };
      const data = await clearLog(param).then((response) => {
        return response.data;
      });
      this.$notify({
        message: "清除成功",
        type: "success",
        duration: 2000,
      });
      this.listLogQuery.page = 1;
      this.listLogQuery.limit = 5;
      await this.getLogList();
    },
  },
};
</script>
